package ch.hslu.gl20vscpudemo;

import java.io.IOException;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;

/**
 * Camera Surface 
 * camera hardware and view handler
 */
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener {

	// interface /////////////////////////////////////////////////////////////////
	public interface Callback {
		public void onPictureTaken(byte[] data);
	}

	// members ///////////////////////////////////////////////////////////////////
	private Context mContext;
	private final int nCameraWidth = 640; // half screen sizes
	private final int nCameraHeight = 696;
	private final SurfaceHolder mHolder;
	private Camera mCamera;
	private Camera.Parameters mCameraParameters;
	private int mCameraPreviewWidth;
	private int mCameraPreviewHeight;
	private int mCameraPictureWidth;
	private int mCameraPictureHeight;
	private Callback mCallback;
	private int nTouchCount;

	// constructor ///////////////////////////////////////////////////////////////
	/**
	 * initialize camera surface view
	 * @param context activity
	 */
	public CameraSurfaceView(Context context) {
		super(context);
		mContext = context;
		mCallback = (Callback) context;

		// default settings for preview and taken picture
		mCameraPreviewWidth = nCameraWidth;
		mCameraPreviewHeight = nCameraHeight;
		mCameraPictureWidth = nCameraWidth;
		mCameraPictureHeight = nCameraHeight;

		// Install a SurfaceHolder.Callback so we get notified when the
		// underlying surface is created and destroyed.
		mHolder = getHolder();
		mHolder.addCallback(this);

		// register the on touch listener
		setOnTouchListener(this);
		nTouchCount = 0;
	}

	// public methods ////////////////////////////////////////////////////////////
	/**
	 * perform autofocus if camera is running 
	 */
	public void setAutoFocus() {
		if (mCamera != null) {
			mCamera.autoFocus(new AutoFocusCallback() {
				public void onAutoFocus(boolean success, Camera camera) {
					Toast.makeText(mContext, "autofocused=" + success, Toast.LENGTH_SHORT).show();
				}
			});
		}
	}

	/** SurfaceHolder.Callback */
	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
		// If your preview can change or rotate, take care of those events here.
		// Make sure to stop the preview before resizing or reformatting it.

		if (mHolder.getSurface() == null) {
			Log.e(this.toString(), "preview surface does not exist");
			return;
		}

		// set preview size and make any resize, rotate or
		// reformatting changes here

		// start preview with new settings
		previewDisplay();
	}

	/** SurfaceHolder.Callback */
	public void surfaceCreated(SurfaceHolder holder) {
		// open camera
		mCamera = getCameraInstance();

		// The Surface has been created, now tell the camera where to draw the
		// preview.
		previewDisplay();
	}

	/** SurfaceHolder.Callback */
	public void surfaceDestroyed(SurfaceHolder holder) {
		// release the camera preview
		try {
			mCamera.stopPreview();
		} catch (final Exception e) {
			Log.e(this.toString(), "tried to stop a non-existent preview");
		}
		if (mCamera != null) {
			mCamera.release(); // release the camera for other applications
			mCamera = null;
		}
	}

	/** View.OnTouchListener */
	public boolean onTouch(View v, MotionEvent event) {
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				if (0 == nTouchCount) {
					nTouchCount++;
					mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
						public void onPictureTaken(byte[] data, Camera camera) {
							/* run callback method */
							mCallback.onPictureTaken(data);
						}
					});
				} else {
					nTouchCount = 0;
					mCamera.startPreview();
				}
				return true;
			default:
				return false;
		}
	}

	// private methods ///////////////////////////////////////////////////////////
	// A safe way to get an instance of the Camera object.
	private static Camera getCameraInstance() {
		Camera c = null;
		try {
			c = Camera.open(); // attempt to get a Camera instance
		} catch (final Exception e) {
			Log.d("getCameraInstance", "Camera is not available (in use or does not exist)");
		}
		return c; // returns null if camera is unavailable
	}

	private void previewDisplay() {
		mCameraParameters = mCamera.getParameters();
		mCameraParameters.setPreviewSize(mCameraPreviewWidth, mCameraPreviewHeight);
		mCameraParameters.setPictureSize(mCameraPictureWidth, mCameraPictureHeight);
		mCamera.setParameters(mCameraParameters);
		try {
			mCamera.setPreviewDisplay(mHolder);
			mCamera.startPreview();
		} catch (final IOException e) {
			Log.d(getClass().toString(), "Error setting camera preview: " + e.getMessage());
		}
	}
}
